/***************************************************************************
 *   Copyright (C) 2007, 2009-2010 by Lasse Liehu                          *
 *   lliehu@kolumbus.fi                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "settingsform.h"

#include <cassert>
#include <sstream>

#include <QSettings>
#include <QPalette>
#include <QMessageBox>
#include <QPushButton>
#include <QWhatsThis>
#include <QDesktopServices>

#include <QMapIterator>

#include "google_reader_notifier_qt.h"
#include "logwidget.h"
#include "googlelogindata.h"
#include "notifiersettings.h"

SettingsForm::SettingsForm(google_reader_notifier_qt& ref, LogWidget& log,
    NotifierSettings& settings, QWidget *parent) : QDialog(parent),
    mRef(ref), mLog(log), mSettings(settings)
{
    ui.setupUi(this);

    populateCheckingIntervalPresets();
    addNumericalDataToNotificationTimeCombo();

#ifndef Q_WS_WIN
    ui.systemIntegrationGroup->hide();
#endif

    // Populate cheking interval combo box with interval presets (we need them
    // to be there before reading the settings)
    QMapIterator<int, QString> iter(mCheckingIntervalPresets);
    int presetsAddedToComboBox = 0;
    while (iter.hasNext() )
    {
        iter.next();
        ui.checkingIntervalCombo->insertItem(presetsAddedToComboBox,
                                             iter.value(), QVariant(iter.key()) );
        ++presetsAddedToComboBox;
    }

    // Make connections
    connect(ui.buttonBox, SIGNAL(accepted() ), this, SLOT(slotSaveSettings() ));
    connect(ui.buttonBox, SIGNAL(rejected() ), this, SIGNAL(ready() ));
    connect(ui.sysTrayCountFont, SIGNAL(currentFontChanged(const QFont&)), this,
        SLOT(updatePreview() ));
    connect(ui.resetUnreadCountWinPos, SIGNAL(clicked()), this,
        SLOT(slotResetUnreadCountWinPos()));
    connect(ui.buttonBox->button(QDialogButtonBox::Help), SIGNAL(clicked()),
        this, SLOT(slotShowHelp() ));
    connect(ui.checkingIntervalCombo, SIGNAL(currentIndexChanged(int)), this,
        SLOT(slotCheckingIntervalComboIndexChanged(int)) );
    connect(ui.account_password_save, SIGNAL(clicked()), this,
        SLOT(slotShowSavePasswordWarn() ));

    // Read current settings
    readSettings();

    // Finishing touches: attributes & stuff
    resize(sizeHint() );
    setAttribute(Qt::WA_DeleteOnClose);
}

void SettingsForm::slotSaveSettings()
{
    //BEGIN Saving settings to memory
    // Saving Google account details
    GoogleLoginData& loginData = mSettings.loginData();
    loginData.setEmail(ui.account_email->text() );
    // save password only if "save password" is on
    if (ui.account_password_save->isChecked() )
    {
        loginData.setPassword(ui.account_password->text() );
    }
    loginData.setSavePassword(ui.account_password_save->isChecked() );

    // Saving checking interval
    // if one of the presets was used
    if (ui.checkingIntervalCombo->currentIndex() != ui.checkingIntervalCombo->count()-1)
    {
        mSettings.setCheckingInterval(ui.checkingIntervalCombo->itemData(
            ui.checkingIntervalCombo->currentIndex() ).toInt() );
    }
    // if custom interval was used
    else
    {
        mSettings.setCheckingInterval(ui.checkingIntervalMinutes->value() +
            ui.checkingIntervalHours->value() * 60);
    }

    // Saving settngs about showing unread count in a floating widget
    mSettings.setUnreadCountDisplayFont(ui.sysTrayCountFont->currentFont() );
    mSettings.setShowUnreadCountInWindow(ui.showUnreadCountInWindow->isChecked() );

    // Saving notification time settings
    NewUnreadItemsNotificationTime notificationTime;
    int notificationTimeInt = ui.newUnreadItemsNotificationTime->itemData(
        ui.newUnreadItemsNotificationTime->currentIndex() ).toInt();
    if (notificationTimeInt == NUINT_Always) notificationTime = NUINT_Always;
    else if (notificationTimeInt == NUINT_Smart) notificationTime = NUINT_Smart;
    else if (notificationTimeInt == NUINT_Never) notificationTime = NUINT_Never;
    else
    {
        mLog.writeToLog("SettingsForm", tr("ERROR: Unsupported value of "
            "settings \'Notification of new unread items\': %1. Falling back to "
            "Smart mode.").arg(ui.newUnreadItemsNotificationTime->currentText()),
                        LogWidget::Debug);
        QMessageBox::critical(this, "Google Reader Notifier Qt", tr("An "
            "unexpected error happened with setting \'Notification of new "
            "unread items\'. Falling back to \'Smart\' mode."));
        notificationTime = NUINT_Smart;
    }
    mSettings.setNotificationTime(notificationTime);

    // Saving autostart settings
    mSettings.setAutostartEnabled(ui.startWhenUserLogsIn->isChecked() );
    //END Saving settings to memory

    // Saving settings to disk
    mSettings.writeSettings();

    emit ready();
}

void SettingsForm::updatePreview()
{
    QFont font = ui.sysTrayCountFont->currentFont();
    font.setBold(true);
    ui.fontWithMinSizePreview->setFont(font);
}

void SettingsForm::slotResetUnreadCountWinPos()
{
    mRef.resetUnreadCountWinPos();
}

void SettingsForm::readSettings()
{
    // Reading Google account data (login data)
    GoogleLoginData& loginData = mSettings.loginData();
    ui.account_email->setText(loginData.email() );
    ui.account_password_save->setChecked(loginData.isPasswordSaved() );
    ui.account_password->setText(loginData.password(GoogleLoginData::Saved) );

    // Show or hide the password line edit according to whether it's saved or not
    if (ui.account_password_save->isChecked() &&
        ( ! ui.account_password->text().isEmpty() )) // if saved
    {
        slotShowSavedPassword();
    }
    else slotHideSavedPassword(); // if not saved

    // Reading checking interval
    QMap<int, QString>::const_iterator iter =
        mCheckingIntervalPresets.find(mSettings.checkingInterval() );
    if (iter != mCheckingIntervalPresets.end() )
    {
        ui.checkingIntervalCombo->setCurrentIndex(
            ui.checkingIntervalCombo->findData(iter.key() ));
    }
    else
    {
        // selecting the item at the last index; it should be "Custom"
        ui.checkingIntervalCombo->setCurrentIndex(
            ui.checkingIntervalCombo->count()-1);
        ui.checkingIntervalHours->setValue(mSettings.checkingInterval()/60);
        ui.checkingIntervalMinutes->setValue(mSettings.checkingInterval()%60);
    }

    // Reading settings about showing the unread count in a floating widget
    ui.sysTrayCountFont->setCurrentFont(mSettings.unreadCountDisplayFont() );
    ui.showUnreadCountInWindow->setChecked(mSettings.isUnreadCountShownInWindow() );

    // Reding notification time settings
    NewUnreadItemsNotificationTime notificationTime =
        mSettings.notificationTime();
    int comboboxId = 0;
    if (notificationTime == NUINT_Always)
    {
        comboboxId = ui.newUnreadItemsNotificationTime->findData(NUINT_Always);
    }
    else if (notificationTime == NUINT_Smart)
    {
        comboboxId = ui.newUnreadItemsNotificationTime->findData(NUINT_Smart);
    }
    else if (notificationTime == NUINT_Never)
    {
        comboboxId = ui.newUnreadItemsNotificationTime->findData(NUINT_Never);
    }
    else
    {
        std::ostringstream strm;
        strm << notificationTime;
        mLog.writeToLog("SettingsForm", tr("ERROR: "
            "newUnreadItemsNotificationTime was %1. Falling back to smart "
            "mode.").arg(strm.str().c_str()), LogWidget::Debug);
        QMessageBox::critical(this, "Google Reader Notifier Qt", tr("An "
            "unexpected error happened with setting \'Notification of new "
            "unread items\'. Falling back to Smart mode."));
        comboboxId = ui.newUnreadItemsNotificationTime->findData(NUINT_Smart);
    }
    if (comboboxId == -1)
    {
        mLog.writeToLog("SettingsForm", tr("ERROR: \'Notification of new unread "
            "items\' setting corresponding to the value of "
            "newUnreadItemsNotificationTime was not found."), LogWidget::Debug);
        QMessageBox::critical(this, "Google Reader Notifier Qt", tr("An "
            "unexpected error happened with setting \'Notification of new "
            "unread items\'."));
    }
    ui.newUnreadItemsNotificationTime->setCurrentIndex(comboboxId);

    // Reading autostart setting
    ui.startWhenUserLogsIn->setChecked(mSettings.isAutostartEnabled() );
}

void SettingsForm::slotShowHelp()
{
    QMessageBox::information(this, "Google Reader Notifier Qt", tr("Help has "
        "not been written yet. Tooltips may help you."));
}

// NOTE newVal is the new value of "Save the password" checkbox
void SettingsForm::slotShowSavePasswordWarn()
{
    if (! ui.account_password_save->isChecked() )
    {
        slotHideSavedPassword();
        return;
    }

    QMessageBox msgBox(this);
    msgBox.setWindowTitle("Google Reader Notifier Qt");
    msgBox.setText(tr("The password will be saved <b>in an unsafe way</b>.") );
    msgBox.setInformativeText(tr("Do you still want to save the password?") );
    msgBox.setDetailedText(tr("The password will be saved in plain text so that "
        "anyone who can read your personal files and knows where to look for it "
        "can discover both your password and username.") );
    QPushButton *yesButton = msgBox.addButton(tr("Save in an unsafe way"),
                                              QMessageBox::YesRole);
    QPushButton *noButton = msgBox.addButton(tr("Don't save"), QMessageBox::NoRole);
    msgBox.setDefaultButton(noButton);
    msgBox.setIcon(QMessageBox::Warning);
    msgBox.exec();
    if (msgBox.clickedButton() == yesButton)
    {
        slotShowSavedPassword();
        ui.account_password->setFocus(Qt::OtherFocusReason);
    }
    else if (msgBox.clickedButton() == noButton)
    {   
        ui.account_password_save->setChecked(false);
    }
    else
    {
        // NOTE this should not happen!
        mLog.writeToLog("SettingsForm", tr("Ended up in else block "
            "in slotShowPasswordWarn, which should be impossible"), LogWidget::Debug);
    }
}

void SettingsForm::slotShowSavedPassword()
{
    ui.account_password->setShown(true);
    ui.account_password->setEnabled(true);
    updateAccNotSetUpWarningVisibilityStatus();
}

void SettingsForm::slotHideSavedPassword()
{
    ui.account_password->setHidden(true);
    ui.account_password->setEnabled(false);
    ui.account_password->clear();
    updateAccNotSetUpWarningVisibilityStatus();
}

void SettingsForm::on_account_email_textEdited()
{
    updateAccNotSetUpWarningVisibilityStatus();
}

void SettingsForm::on_account_password_textEdited()
{
    updateAccNotSetUpWarningVisibilityStatus();
}

void SettingsForm::on_newUnreadItemsNotificationTimeHelp_clicked()
{
    QMessageBox::information(this, tr("Help not yet written"), tr("Help has not yet "
        "been written for this feature."));
}

void SettingsForm::updateAccNotSetUpWarningVisibilityStatus()
{
    ui.accNotSetUpWarningLabel->setVisible( ui.account_email->text().isEmpty() ||
        (ui.account_password_save->isChecked() && ui.account_password->text().isEmpty() ));
}

void SettingsForm::slotCheckingIntervalComboIndexChanged(int index)
{
    // If checking interval isn't "Custom", hiding the widgets for settings up
    // the custom interval, and vice versa

    bool hide = ui.checkingIntervalCombo->currentIndex() !=
        ui.checkingIntervalCombo->count() - 1;

    ui.checkingIntervalHours->setHidden(hide);
    ui.checkingIntervalHoursLabel->setHidden(hide);
    ui.checkingIntervalMinutes->setHidden(hide);
    ui.checkingIntervalMinutesLabel->setHidden(hide);
}

void SettingsForm::populateCheckingIntervalPresets()
{
    mCheckingIntervalPresets.insert(15, tr("15 minutes") );
    mCheckingIntervalPresets.insert(30, tr("30 minutes") );
    mCheckingIntervalPresets.insert(45, tr("45 minutes") );
    mCheckingIntervalPresets.insert(60, tr("1 hour") );
    mCheckingIntervalPresets.insert(120, tr("2 hours") );
    mCheckingIntervalPresets.insert(180, tr("3 hours") );
    mCheckingIntervalPresets.insert(300, tr("5 hours") );
}

/**
 * This member function assumes that the combo box contains the following
 * entries: Alwaysm Smart and Never, and only these and in this order.
 */
void SettingsForm::addNumericalDataToNotificationTimeCombo()
{
    assert(ui.newUnreadItemsNotificationTime->count() == 3);
    ui.newUnreadItemsNotificationTime->setItemData(0, NUINT_Always);
    ui.newUnreadItemsNotificationTime->setItemData(1, NUINT_Smart);
    ui.newUnreadItemsNotificationTime->setItemData(2, NUINT_Never);
}
